import type { CheckLeftIsExtendsRight, Not, Or } from "../common";
import type { Stringify, Split } from "../string";
import type { GetTuple, Pop } from "../array";

type NumberLike = number | `${number}`;

/**
 * #### 判断是否为0或“0”
 * @category Number
 * @example
 * ```ts
 * type test1 = IsZero<0>; // true
 * type test2 = IsZero<"0">; // true
 * ```
 */
export type IsZero<N extends NumberLike> = CheckLeftIsExtendsRight<N, 0 | "0">;

/**
 * #### 判断是否为正数
 * @category Number
 * @example
 * ```ts
 * type test1 = IsPositive<"-1">; // false
 * type test2 = IsPositive<"1">; // true
 * ```
 */
export type IsPositive<N extends NumberLike> = IsZero<N> extends true
  ? false
  : CheckLeftIsExtendsRight<
      Stringify<N> extends `${"-"}${infer R}` ? R : false,
      false
    >;

/**
 * #### 判断是否为负数
 * @category Number
 * @example
 * ```ts
 * type test1 = IsNegative<"-1">; // true
 * type test2 = IsNegative<"1">; // false
 * type test3 = IsNegative<0>; // false
 * ```
 */
export type IsNegative<N extends NumberLike> = IsZero<N> extends true
  ? false
  : Not<IsPositive<N>>;

/**
 * #### 判断是否为浮点数
 * @category Number
 * @example
 * ```ts
 * type test1 = IsFloat<5.4>; // true
 * type test2 = IsFloat<5>; // false
 * ```
 */
export type IsFloat<
  N extends NumberLike,
  OnlyCheckPoint extends boolean = true
> = Stringify<N> extends `${infer L}${"."}${infer R}`
  ? OnlyCheckPoint extends true
    ? true
    : false
  : false;

/**
 * #### 判断是否为整数
 * @category Number
 * @example
 * ```ts
 * type test1 = IsInt<5.4>; // false
 * type test2 = IsInt<5>; // true
 * ```
 */
export type IsInt<
  N extends NumberLike,
  OnlyCheckPoint extends boolean = true
> = Not<IsFloat<N, OnlyCheckPoint>>;

/**
 * #### 判断两数是否相等
 * @category Number
 * @example
 * ```ts
 * type test1 = IsEqual<5, 4>; // false
 * type test2 = IsEqual<4, 5>; // false
 * ```
 */
export type IsEqual<
  L extends NumberLike,
  R extends NumberLike,
  Strict extends boolean = true
> = Strict extends true
  ? CheckLeftIsExtendsRight<L, R>
  : CheckLeftIsExtendsRight<Stringify<L>, Stringify<R>>;

/**
 * #### 判断两数是否不相等
 * @category Number
 * @example
 * ```ts
 * type test1 = IsNotEqual<5, 4>; // true
 * type test2 = IsNotEqual<4, 5>; // true
 * ```
 */
export type IsNotEqual<
  L extends NumberLike,
  R extends NumberLike,
  Strict extends boolean = true
> = Not<IsEqual<L, R, Strict>>;

type IntAddSingleHepler<N1 extends number, N2 extends number> = [
  ...GetTuple<N1>,
  ...GetTuple<N2>
]["length"];

/**
 * #### 两数相加
 * @category Number
 * @example
 * ```ts
 * type test1 = IntAddSingle<5, 4>; // 9
 * type test2 = IntAddSingle<4, 5>; // 9
 * ```
 */
export type IntAddSingle<
  N1 extends number,
  N2 extends number
> = IntAddSingleHepler<N1, N2> extends number
  ? IntAddSingleHepler<N1, N2>
  : number;

type CompareHepler<
  N1 extends number,
  N2 extends number,
  A1 extends unknown[] = GetTuple<N1>,
  A2 extends unknown[] = GetTuple<N2>
> = IsNotEqual<N1, N2, true> extends true
  ? Or<IsZero<A1["length"]>, IsZero<A2["length"]>> extends true
    ? IsZero<A1["length"]> extends true
      ? false
      : true
    : CompareHepler<Pop<A1>["length"], Pop<A2>["length"]>
  : false;

/**
 * #### 比较大小
 * @category Number
 * @example
 * ```ts
 * type test1 = Compare<5, 4>; // true
 * type test2 = Compare<4, 5>; // false
 * ```
 */
export type Compare<N1 extends number, N2 extends number> = CompareHepler<
  N1,
  N2
>;

type IntMinusSingleAbsHelper<
  N1 extends number,
  N2 extends number,
  A1 extends unknown[] = GetTuple<N1>,
  A2 extends unknown[] = GetTuple<N2>
> = IsNotEqual<N1, N2, true> extends true
  ? Or<IsZero<A1["length"]>, IsZero<A2["length"]>> extends true
    ? IsZero<A1["length"]> extends true
      ? A2["length"]
      : A1["length"]
    : IntMinusSingleAbsHelper<Pop<A1>["length"], Pop<A2>["length"]>
  : 0;

/**
 * #### 两数相减绝对值
 * @category Number
 * @example
 * ```ts
 * type test1 = IntMinusSingleAbs<5, 4>; // 1
 * type test2 = IntMinusSingleAbs<4, 5>; // 1
 * ```
 */
export type IntMinusSingleAbs<
  N1 extends number,
  N2 extends number
> = IntMinusSingleAbsHelper<N1, N2>;

/**
 * #### 两数相减
 * @category Number
 * @example
 * ```ts
 * type test1 = Subtract<5, 4>; // 1
 * type test2 = Subtract<4, 5>; // never
 * ```
 */
export type Subtract<
  N1 extends number,
  N2 extends number
> = GetTuple<N1> extends [...arr1: GetTuple<N2>, ...arr2: infer Rest]
  ? Rest["length"]
  : never;

/**
 * #### 两数相乘
 * @category Number
 * @example
 * ```ts
 * type test1 = Mutiply<4, 8>; // 32
 * ```
 */
export type Mutiply<
  N1 extends number,
  N2 extends number,
  Result extends unknown[] = []
> = N2 extends 0
  ? Result["length"]
  : Mutiply<N1, Subtract<N2, 1>, [...GetTuple<N1>, ...Result]>;
// type sub=Mutiply<4, 8>;

/**
 * #### 两数相除
 * @category Number
 * @example
 * ```ts
 * type test1 = Divide<8, 4>; // 2
 * ```
 */
export type Divide<
  N1 extends number,
  N2 extends number,
  Result extends unknown[] = []
> = N1 extends 0
  ? Result["length"]
  : Divide<Subtract<N1, N2>, N2, [unknown, ...Result]>;

type divide = Divide<6, 2>;

type GetHalfHelper<N extends number, Offset extends number = 0> = IsEqual<
  IntAddSingle<Offset, Offset>,
  N
> extends true
  ? Offset
  : IsEqual<IntAddSingle<IntAddSingle<Offset, Offset>, 1>, N> extends true
  ? IntAddSingle<Offset, 1>
  : GetHalfHelper<N, IntAddSingle<Offset, 1>>;

/**
 * #### 获取一半
 * @category Number
 * @example
 * ```ts
 * type test = GetHalf<4>; // 2
 * ```
 */
export type GetHalf<N extends number> = GetHalfHelper<N>;

type Map = {
  "0": [];
  "1": [1];
  "2": [...Map["1"], 1];
  "3": [...Map["2"], 1];
  "4": [...Map["3"], 1];
  "5": [...Map["4"], 1];
  "6": [...Map["5"], 1];
  "7": [...Map["6"], 1];
  "8": [...Map["7"], 1];
  "9": [...Map["8"], 1];
};

type Make10Array<T extends any[]> = [
  ...T,
  ...T,
  ...T,
  ...T,
  ...T,
  ...T,
  ...T,
  ...T,
  ...T,
  ...T
];

type ToNumberHelper<
  S extends string,
  L extends any[] = []
> = S extends `${infer F}${infer R}`
  ? ToNumberHelper<
      R,
      [...Make10Array<L>, ...(F extends keyof Map ? Map[F] : never)]
    >
  : L["length"];

/**
 * #### 字符串转数字
 * @category Number
 * @example
 * ```ts
 * type test = ToNumber<"123">; // 123
 * ```
 */
export type ToNumber<S extends string> = ToNumberHelper<S>;

// type test = IntAddSingle<1, 3>;
// type compare = Compare<5, 4>;
// type minus = IntMinusSingleAbs<5, 4>;
// type minus2 = IntMinusSingleAbs<4, 5>;
// type half = GetHalf<4>;
// type toNumber = ToNumber<"123">;
type add = IntAddSingle<5, 3>;
type isnegative = IsNegative<-8>;
